/**
 * 
 */
package UsedCar;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;
import uchicago.src.sim.util.Random;

/**
 * 產生品質與知識的關係
 * 
 * @author August F.Y. Chao
 * 
 */
public class Quality {
	/**
	 * @param knows
	 *            知識總物件
	 */
	public Knowledges knows;
	protected String[] totalQuals;
	/**
	 * @param QUALITY_NUM_EACH_TYPE
	 *            每種車型多少品質
	 */
	protected int QUALITY_NUM_EACH_TYPE = 0;
	/**
	 * @param q2k
	 *            品質對應的知識
	 */
	Hashtable<String, String[]> q2k = new Hashtable<String, String[]>();
	/**
	 * @param k2p
	 *            知識對應到的品質
	 */
	Hashtable<String, String[]> k2q = new Hashtable<String, String[]>();
	/**
	 * @param q2p
	 *            品質對應到的價格
	 */
	Hashtable<String, Integer> q2p = new Hashtable<String, Integer>();
	/**
	 * @param AVG_RATIO_Q2K
	 *            平均每個品質需要多少知識去評量
	 */
	public static final int AVG_RATIO_Q2K = 5;

	/**
	 * @param total_quality_price
	 *            所有品質的總價
	 */
	public int max_quality_price = 0;

	/**
	 * @param INIT_PRICE_MIN
	 *            單一品質的最小價值
	 * @param INIT_PRICE_MAX
	 *            單一品質的最大價值
	 */
	public static final int INIT_PRICE_MIN = 100, INIT_PRICE_MAX = 500;

	/**
	 * 建構子
	 * 
	 * @param knows
	 *            世界知識
	 * @param initNum
	 *            開始的品質量
	 */
	public Quality(Knowledges knows, int initNum) {
		// 產生亂數種子
		long s = System.currentTimeMillis();
		Random.setSeed(s);
		this.setKnows(knows);
		this.initQualityDep(initNum);
	}

	/**
	 * 產生品質與知識的相依
	 * 
	 * @param num
	 *            品質總量
	 */
	public void initQualityDep(int num) {
		int ct = this.knows.getCarTypes();
		this.setQUALITY_NUM_EACH_TYPE(num);
		totalQuals = new String[num * ct];
		for (int j = 0; j < ct; j++) {
			for (int i = 0; i < this.getQUALITY_NUM_EACH_TYPE(); i++) {
				String nameQ = "T" + j + "_Q" + i;
				totalQuals[j * this.getQUALITY_NUM_EACH_TYPE() + i] = nameQ;
				this.q2k.put(nameQ,
						this.knows.getRandKnowsEachType(AVG_RATIO_Q2K, j));
			}
		}
		this.createKnowledgeDep();
		this.initQualityValue();
	}

	/**
	 * 依預設的品質與知識相依建立反向相依
	 * 
	 * @see initQualityDep
	 */
	protected void createKnowledgeDep() {
		// 取出 Hash 的 所有 key
		Enumeration<String> qs = q2k.keys();
		while (qs.hasMoreElements()) { // 一個一個跑
			// 取得 key
			String qkey = qs.nextElement();

			// 取出 key 中的 ArrayList
			String[] qKnows = q2k.get(qkey);
			for (int i = 0; i < qKnows.length; i++) {

				String kKey = qKnows[i];

				// 是否已經有預設內容
				if (!k2q.containsKey(kKey)) {
					// 若無...產生一個 放到 HashTable 中
					String[] tmp = new String[1];
					tmp[0] = qkey;
					k2q.put(kKey, tmp);
				} else {
					// 若有...加一個到 HashTable 中
					String[] inHash = k2q.get(kKey);
					String[] tmp = new String[inHash.length + 1];
					for (int j = 0; j < inHash.length; j++) {
						tmp[j] = inHash[j];
					}
					tmp[inHash.length] = qkey;
					k2q.put(kKey, tmp);

				}

			}

		}
	}

	/**
	 * 產生隨機品質價值
	 */
	public void initQualityValue() {
		int[] each_qValue = new int[knows.carTypes];
		// 取出 Hash 的 所有 key
		Enumeration<String> qs = q2k.keys();
		Random.createUniform();
		while (qs.hasMoreElements()) { // 一個一個跑
			// 取得 key
			String qkey = qs.nextElement();

			int rand_value = Random.uniform.nextIntFromTo(INIT_PRICE_MIN,
					INIT_PRICE_MAX);
			this.q2p.put(qkey, rand_value);

			each_qValue[Integer.valueOf(qkey.split("_")[0].replace("T", ""))] += rand_value;
		}

		int max_value = 0;
		for (int i = 0; i < knows.carTypes; i++) {
			if (each_qValue[i] > max_value) {
				max_value = each_qValue[i];
			}
		}

		// 設定最大的品質價值
		max_quality_price = max_value;
	}

	public String[] getQualList(int ct) {
		String[] rQual = new String[getQUALITY_NUM_EACH_TYPE()];

		for (int i = 0; i < getQUALITY_NUM_EACH_TYPE(); i++) {
			rQual[i] = this.totalQuals[this.getQUALITY_NUM_EACH_TYPE() * ct + i];
		}
		this.knows.listKnows(rQual);
		return rQual;
	}

	/**
	 * 列出品質的個別價值
	 */
	public void listPrice() {
		int ct = this.knows.getCarTypes();
		for (int j = 0; j < ct; j++) {
			for (int i = 0; i < this.getQUALITY_NUM_EACH_TYPE(); i++) {
				String nameQ = "T" + j + "_Q" + i;

				System.out.println("K(" + nameQ + ") = " + q2p.get(nameQ)
						+ " | " + this.knows.listKnows(q2k.get(nameQ)));
			}
		}
	}

	/**
	 * 列出所有的品質字串
	 * 
	 * @param quals
	 *            一個品質陣列
	 * @return 字串
	 */
	public String listQual(String[] quals) {
		return this.knows.listKnows(quals);
	}

	/**
	 * 產生隨機的品質
	 * 
	 * @param ct
	 *            車型
	 * @param max
	 *            最多品質量
	 * @return 品質字串
	 */
	public String[] getRandQual(int ct, int max) {
		ArrayList<String> reQual = new ArrayList<String>();

		for (int j = 0; j < this.getQUALITY_NUM_EACH_TYPE(); j++) {
			Random.createUniform();
			boolean choose = (Random.uniform.nextIntFromTo(0,
					this.getQUALITY_NUM_EACH_TYPE()) < max);
			if (choose) {
				reQual.add("T" + ct + "_Q" + j);
			}
		}

		String[] res = (String[]) reQual.toArray(new String[reQual.size()]);
		return res;
	}

	/**
	 * 取得品質價格
	 * 
	 * @param qual
	 *            品質
	 * @return 價格
	 */
	public int getPrice(String qual) {
		return this.q2p.get(qual);
	}

	/**
	 * 取得所需的知識
	 * 
	 * @param qual
	 *            品質
	 */
	public String[] getKnows(String qual) {
		return q2k.get(qual);
	}

	// ---------------------------------------------------------------------------------------------------------------------------------------------//
	// 變數的 setter and getter
	// ---------------------------------------------------------------------------------------------------------------------------------------------//
	public Knowledges getKnows() {
		return knows;
	}

	public void setKnows(Knowledges knows) {
		this.knows = knows;
	}

	public int getQUALITY_NUM_EACH_TYPE() {
		return QUALITY_NUM_EACH_TYPE;
	}

	public void setQUALITY_NUM_EACH_TYPE(int qUALITY_NUM_EACH_TYPE) {
		QUALITY_NUM_EACH_TYPE = qUALITY_NUM_EACH_TYPE;
	}

	public int getMax_quality_price() {
		return max_quality_price;
	}

	public void setMax_quality_price(int max_quality_price) {
		this.max_quality_price = max_quality_price;
	}
}
